// --------------------------------------------------------------------------------------------------------------------
// <copyright file="NatwestDataParser.cs" company="Concept Architecture">
//   (c) 2010 Muhammad Umer Farooq
// </copyright>
// <summary>
//   Defines the <seealso cref="NatwestDataParser" /> type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Hisaab.Business.Parser
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.Contracts;
    using System.IO;
    using System.Linq;
    using Entities;
    using Hisaab.Data.Interfaces;
    using LINQtoCSV;
    using Microsoft.Practices.ServiceLocation;

    /// <summary>
    /// Defines the <seealso cref="NatwestDataParser"/> type.
    /// </summary>
    public class NatwestDataParser : IBankDataParser
    {
        /// <summary>
        /// Member variable _accountRepository
        /// </summary>
        private readonly IAccountRepository _accountRepository;

        /// <summary>
        /// Initializes a new instance of the <see cref="NatwestDataParser"/> class.
        /// </summary>
        public NatwestDataParser()
            : this(ServiceLocator.Current.GetInstance<IAccountRepository>())
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="NatwestDataParser"/> class.
        /// </summary>
        /// <param name="accountRepository">The account manager.</param>
        public NatwestDataParser(IAccountRepository accountRepository)
        {
            Contract.Requires<ArgumentNullException>(accountRepository != null);

            _accountRepository = accountRepository;
        }

        /// <summary>
        /// Imports the CSV.
        /// </summary>
        /// <param name="fileName">The fileName.</param>
        /// <returns>Transactions imported from csv</returns>
        public IEnumerable<Transaction> ImportCsv(string fileName)
        {
            var context = new CsvContext();
            var fixedFileName = PreProcessFile(fileName);
            var natwestData = context.Read<NatwestDataItem>(
                fixedFileName,
                new CsvFileDescription { SeparatorChar = ',', FirstLineHasColumnNames = true });

            var result = natwestData
                .Select(dataItem => new Transaction
                                        {
                                            Date = dataItem.Date,
                                            Amount = Math.Abs(dataItem.Value),
                                            TransactionType = dataItem.Value < 0 ? TransactionTypes.Expanse : TransactionTypes.Income,
                                            Title = dataItem.Description,
                                            Account = GetAccountIdFromAccountNumber(dataItem.AccountNumber)
                                        })
                .ToList();

            return result.ToList();
        }

        /// <summary>
        /// Pres the process file.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <returns>Path of file that is fixed. This is a file created in temporary folder and will be cleaned up automatically</returns>
        private string PreProcessFile(string fileName)
        {
            var fixedFile = Path.GetTempFileName();
            using (var wtr = new StreamWriter(fixedFile))
            {
                foreach (var line in File.ReadAllLines(fileName))
                {
                    wtr.WriteLine(line.Trim(new[] { ',' }));
                }

                wtr.Flush();
            }

            return fixedFile;
        }

        /// <summary>
        /// Gets the account id from account number.
        /// </summary>
        /// <param name="accountNumber">The account number.</param>
        /// <returns>Account Id for given account</returns>
        private int GetAccountIdFromAccountNumber(string accountNumber)
        {
            string accNumber = accountNumber.Split('-')[1].Trim();
            var account = _accountRepository
                            .Query(new Data.Entities.Account { AccountNumber = accNumber })
                            .FirstOrDefault();

            return account != null ? account.Id : 0;
        }

        /// <summary>
        /// Defines the <seealso cref="NatwestDataItem"/> type.
        /// Date, Type, Description, Value, Balance, Account Name, Account Number
        /// </summary>
        public class NatwestDataItem
        {
            /// <summary>
            /// Gets or sets the date.
            /// </summary>
            /// <value>
            /// The date in format dd/MM/YYYY e.g. 03/01/2012
            /// </value>
            [CsvColumn(Name = "Date", FieldIndex = 0)]
            public DateTime Date { get; set; }

            /// <summary>
            /// Gets or sets the type.
            /// </summary>
            /// <value>
            /// The type.
            /// </value>
            [CsvColumn(Name = "Type", FieldIndex = 1)]
            public string Type { get; set; }

            /// <summary>
            /// Gets or sets the description.
            /// </summary>
            /// <value>
            /// The description.
            /// </value>
            [CsvColumn(Name = "Description", FieldIndex = 2)]
            public string Description { get; set; }

            /// <summary>
            /// Gets or sets the value.
            /// </summary>
            /// <value>
            /// The value.
            /// </value>
            [CsvColumn(Name = "Value", FieldIndex = 3)]
            public decimal Value { get; set; }

            /// <summary>
            /// Gets or sets the balance.
            /// </summary>
            /// <value>
            /// The balance.
            /// </value>
            [CsvColumn(Name = "Balance", FieldIndex = 4)]
            public string Balance { get; set; }

            /// <summary>
            /// Gets or sets the name of the account.
            /// </summary>
            /// <value>
            /// The name of the account.
            /// </value>
            [CsvColumn(Name = "Account Name", FieldIndex = 5)]
            public string AccountName { get; set; }

            /// <summary>
            /// Gets or sets the account number.
            /// </summary>
            /// <value>
            /// The account sort code and number  e.g 123456-12345678
            /// </value>
            [CsvColumn(Name = "Account Number", FieldIndex = 6)]
            public string AccountNumber { get; set; }
        }
    }
}